ZgRNS Git Node
π Files β’ βΈ Work (0) β’ πΉ Commits (470) β’ β Branches (4) β’ β Tags (61) β’ β₯ Thanks (1) β’ π Stats
>LXMFy
Python framework for LXMF bots on the Reticulum Network.
Features
ββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Category β Capabilities β
ββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Core β Interactive CLI, command prefixes, cron-style task scheduler, middleware and eveβ¦ β
β Connectivity β Direct delivery with propagation fallback, auto-peering, RNS links, opportunistiβ¦ β
β Security β Spam protection, role-based permissions, identity pinning, message signature polβ¦ β
β NLP β Local offline intent classification, type-hinted argument parsing β
β Extensions β Python cogs, external script cogs (Bash, Go, C, and others), subprocess sandboxiβ¦ β
β Storage β JSON, SQLite, and in-memory backends, crash-safe outgoing message persistence β
β Reliability β Stability and stress tests, chaos engineering hooks, resource leak checks β
β UX β Help on first message, auto-generated help menus, customizable bot icons, attachβ¦ β
ββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Installation
From PyPI
T282828
T8b949e# pip
pip install lxmfy
T8b949e# pipx
pipx install lxmfy
From source
T282828
git clone https://github.com/Quad4-Software/LXMFy.git
Tffa657cd LXMFy
poetry install
Usage
T282828
lxmfy
Create a bot project:
T282828
lxmfy create
Debug send and receive:
T282828
lxmfy debug
lxmfy debug --config ./config --output ./lxmfy-debug-report.txt
lxmfy debug probe <destination_hash> --request-path --wait T79c0ff30
lxmfy debug send <destination_hash>
lxmfy debug receive
lxmfy debug compare <hash_a> <hash_b>
Doctor mode prints a verdict and next steps, then categorized checks (OS, shared vs owned instance, disk permissions, interfaces, announce, send pipeline / storage history, receive readiness). It saves a privacy-redacted T383838lxmfy-debug-*.txt you can share. Colors turn off when stdout is not a TTY, when T383838NO_COLOR is set, or when Windows VT is unavailable. Use T383838--no-color or T383838NO_COLOR=1 for plain output.
Docker
Build and run
From the project root:
T282828
docker build -t lxmfy-test .
T282828
docker run -d Tffea00\
--name lxmfy-test-bot Tffea00\
-v Tff7b72$(Tffa657pwdTff7b72)/config:/bot/config Tffea00\
-v Tff7b72$(Tffa657pwdTff7b72)/.reticulum:/root/.reticulum Tffea00\
--restart unless-stopped Tffea00\
lxmfy-test
Host networking (AutoInterface):
T282828
docker run -d Tffea00\
--name lxmfy-test-bot Tffea00\
--network host Tffea00\
-v Tff7b72$(Tffa657pwdTff7b72)/config:/bot/config Tffea00\
-v Tff7b72$(Tffa657pwdTff7b72)/.reticulum:/root/.reticulum Tffea00\
--restart unless-stopped Tffea00\
lxmfy-test
Build a wheel
T282828
docker build -f docker/Dockerfile.Build -t lxmfy-wheel-builder .
docker run --rm -v Ta5d6ff"Tff7b72$(Tffa657pwdTff7b72)Ta5d6ff/dist_output:/outputTa5d6ff" lxmfy-wheel-builder
That copies the built wheel into T383838./dist_output.
Example
T282828
Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3LXMFBotTb4b4b4, Te6edf3load_cogs_from_directory
Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffLXMFy Test BotTa5d6ff"Tb4b4b4, T8b949e# Name of the bot that appears on the network.
Te6edf3announceTff7b72=T79c0ff5400Tb4b4b4, T8b949e# Announce every hour, set to 0 to disable.
Te6edf3announce_enabledTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Set to False to disable all announces (both initial and periodic)
Te6edf3announce_immediatelyTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Set to False to disable initial announce
Te6edf3adminsTff7b72=Tb4b4b4[Ta5d6ff"Ta5d6ffyour_lxmf_hash_hereTa5d6ff"Tb4b4b4]Tb4b4b4, T8b949e# List of admin hashes.
Te6edf3hot_reloadingTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Enable hot reloading.
Te6edf3command_prefixTff7b72=Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4, T8b949e# Set to None to process all messages as commands.
Te6edf3cogs_dirTff7b72=Ta5d6ff"Ta5d6ffcogsTa5d6ff"Tb4b4b4, T8b949e# Specify cogs directory name.
Te6edf3rate_limitTff7b72=T79c0ff5Tb4b4b4, T8b949e# 5 messages per minute
Te6edf3cooldownTff7b72=T79c0ff5Tb4b4b4, T8b949e# 5 seconds cooldown
Te6edf3max_warningsTff7b72=T79c0ff3Tb4b4b4, T8b949e# 3 warnings before ban
Te6edf3warning_timeoutTff7b72=T79c0ff300Tb4b4b4, T8b949e# Warnings reset after 5 minutes
Te6edf3signature_verification_enabledTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Enable cryptographic signature verification
Te6edf3require_message_signaturesTff7b72=Tff7b72FalseTb4b4b4, T8b949e# Allow unsigned messages but log them
Te6edf3propagation_fallback_enabledTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Enable propagation fallback after direct delivery fails
Te6edf3propagation_nodeTff7b72=Ta5d6ff"Ta5d6ffyour_propagation_node_hash_hereTa5d6ff"Tb4b4b4, T8b949e# Manual propagation node (optional)
Te6edf3autopeer_propagationTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Auto-discover propagation nodes (optional)
Te6edf3autopeer_maxdepthTff7b72=T79c0ff4Tb4b4b4, T8b949e# Max hops for auto-peering (default: 4)
Te6edf3enable_propagation_nodeTff7b72=Tff7b72FalseTb4b4b4, T8b949e# Run as propagation node (default: False)
Te6edf3message_storage_limit_mbTff7b72=T79c0ff500Tb4b4b4, T8b949e# Storage limit in MB for propagation node (default: 500)
Te6edf3direct_delivery_retriesTff7b72=T79c0ff3Tb4b4b4, T8b949e# Number of direct delivery attempts before falling back to propagation
Te6edf3landlock_enabledTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Linux Landlock LSM sandbox for the bot process (default)
Te6edf3external_cogs_sandbox_enabledTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Sandbox external script cogs on Linux
Te6edf3external_cogs_sandbox_typeTff7b72=Ta5d6ff"Ta5d6ffautoTa5d6ff"Tb4b4b4, T8b949e# auto, landlock, bwrap, firejail, or none
Tb4b4b4)
Te6edf3load_cogs_from_directoryTb4b4b4(Te6edf3botTb4b4b4)
Tf0883e@botTff7b72.Td2a8ffcommandTb4b4b4(Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffpingTa5d6ff"Tb4b4b4, Te6edf3descriptionTff7b72=Ta5d6ff"Ta5d6ffTest if bot is responsiveTa5d6ff"Tb4b4b4)
Tff7b72def Td2a8ffpingTb4b4b4(Te6edf3ctxTb4b4b4)Tb4b4b4:
Te6edf3ctxTff7b72.Td2a8ffreplyTb4b4b4(Ta5d6ff"Ta5d6ffPong!Ta5d6ff"Tb4b4b4)
Tf0883e@botTff7b72.Td2a8ffcommandTb4b4b4(Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffechoTa5d6ff"Tb4b4b4, Te6edf3descriptionTff7b72=Ta5d6ff"Ta5d6ffEcho a messageTa5d6ff"Tb4b4b4, Te6edf3admin_onlyTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72def Td2a8ffechoTb4b4b4(Te6edf3ctxTb4b4b4, Te6edf3messageTb4b4b4: Tffa657strTb4b4b4)Tb4b4b4:
Te6edf3ctxTff7b72.Td2a8ffreplyTb4b4b4(Te6edf3messageTb4b4b4)
Te6edf3botTff7b72.Td2a8ffrunTb4b4b4(Tb4b4b4)
RRC (Reticulum Relay Chat)
Bots can join RRC hubs as ordinary clients over RNS Links with CBOR envelopes:
T282828
Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3LXMFBotTb4b4b4, Te6edf3RRCMessage
Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffRoomBotTa5d6ff"Tb4b4b4,
Te6edf3rrc_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3rrc_hubsTff7b72=Tb4b4b4[Ta5d6ff"Ta5d6ffyour_rrc_hub_destination_hashTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3rrc_roomsTff7b72=Tb4b4b4[Ta5d6ff"Ta5d6fflobbyTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3rrc_nickTff7b72=Ta5d6ff"Ta5d6ffRoomBotTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tf0883e@botTff7b72.Td2a8ffon_rrc
Tff7b72def Td2a8ffon_rrcTb4b4b4(Te6edf3eventTb4b4b4, Te6edf3clientTb4b4b4, Te6edf3payloadTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3event Tff7b72== Ta5d6ff"Ta5d6ffmsgTa5d6ff" Tff7b72and Tffa657isinstanceTb4b4b4(Te6edf3payloadTb4b4b4, Te6edf3RRCMessageTb4b4b4) Tff7b72and Te6edf3payloadTff7b72.Td2a8ffmentionTb4b4b4:
Te6edf3clientTff7b72.Td2a8ffsend_messageTb4b4b4(Te6edf3payloadTff7b72.Td2a8ffroomTb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffHeard you, Tffd700{Te6edf3payloadTff7b72.Td2a8ffnickTffd700}Ta5d6ff"Tb4b4b4)
Te6edf3botTff7b72.Td2a8ffrunTb4b4b4(Tb4b4b4)
Or connect at runtime with T383838bot.connect_rrc(hub_hash, rooms=["lobby"]).
Hub sessions persist across restarts by default (T383838rrc_persist_sessions=True). Outgoing LXMF messages are also persisted by default (T383838message_persistence_enabled=True) so a crash mid-queue does not drop them. The outbound queue is bounded (T383838message_queue_size, default 50) and drops the oldest message when full.
Propagation Node Configuration
LXMFy supports three modes for propagation node usage.
Manual configuration
Set a specific propagation node by hash:
T282828
Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffMyBotTa5d6ff"Tb4b4b4,
Te6edf3propagation_fallback_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3propagation_nodeTff7b72=Ta5d6ff"Ta5d6ffyour_propagation_node_hash_hereTa5d6ff"Tb4b4b4,
Te6edf3direct_delivery_retriesTff7b72=T79c0ff3Tb4b4b4,
Tb4b4b4)
Automatic discovery (auto-peering)
Discover propagation nodes from network announces:
T282828
Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffMyBotTa5d6ff"Tb4b4b4,
Te6edf3propagation_fallback_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3autopeer_propagationTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3autopeer_maxdepthTff7b72=T79c0ff4Tb4b4b4,
Tb4b4b4)
The bot peers with suitable nodes within T383838autopeer_maxdepth hops.
Run as a propagation node
Store and forward messages for offline recipients:
T282828
Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffMyPropagationBotTa5d6ff"Tb4b4b4,
Te6edf3enable_propagation_nodeTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3message_storage_limit_mbTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
T383838message_storage_limit_mb caps disk use. Set to 0 for unlimited storage (not recommended).
Querying propagation status
T282828
Te6edf3status Tff7b72= Te6edf3botTff7b72.Td2a8ffget_propagation_node_statusTb4b4b4(Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCurrent outbound node: Tffd700{Te6edf3statusTb4b4b4[Ta5d6ff'Ta5d6ffcurrent_outbound_nodeTa5d6ff'Tb4b4b4]Tffd700}Ta5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffDiscovered peers: Tffd700{Te6edf3statusTb4b4b4[Ta5d6ff'Ta5d6ffdiscovered_peersTa5d6ff'Tb4b4b4]Tffd700}Ta5d6ff"Tb4b4b4)
Setting the propagation node at runtime
T282828
Te6edf3botTff7b72.Td2a8ffset_propagation_nodeTb4b4b4(Ta5d6ff"Ta5d6ffnew_propagation_node_hashTa5d6ff"Tb4b4b4)
Storage limits
T282828
Te6edf3stats Tff7b72= Te6edf3botTff7b72.Td2a8ffget_propagation_storage_statsTb4b4b4(Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffStorage used: Tffd700{Te6edf3statsTb4b4b4[Ta5d6ff'Ta5d6ffstorage_size_mbTa5d6ff'Tb4b4b4]Tffd700:Ta5d6ff.2fTffd700}Ta5d6ff MBTa5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffStorage limit: Tffd700{Te6edf3statsTb4b4b4[Ta5d6ff'Ta5d6ffstorage_limit_mbTa5d6ff'Tb4b4b4]Tffd700}Ta5d6ff MBTa5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffUtilization: Tffd700{Te6edf3statsTb4b4b4[Ta5d6ff'Ta5d6ffutilization_percentTa5d6ff'Tb4b4b4]Tffd700:Ta5d6ff.1fTffd700}Ta5d6ff%Ta5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffMessages stored: Tffd700{Te6edf3statsTb4b4b4[Ta5d6ff'Ta5d6ffmessage_countTa5d6ff'Tb4b4b4]Tffd700}Ta5d6ff"Tb4b4b4)
Te6edf3botTff7b72.Td2a8ffset_message_storage_limitTb4b4b4(Te6edf3megabytesTff7b72=T79c0ff1000Tb4b4b4)
Propagation notes
β’ Without manual config, auto-peering, or running as a node, messages that need propagation fail
β’ You can combine modes (manual node plus auto-peering as backup)
β’ A propagation-node bot still sends and receives normally
β’ Auto-peering respects T383838autopeer_maxdepth so distant nodes are skipped
Security and Sandboxing
On Linux kernels with Landlock support (5.13+), LXMFy can restrict filesystem access for the bot process and for external script cogs.
Bot process sandbox
When T383838landlock_enabled=True (default), the bot applies a Landlock LSM sandbox after startup. System paths are read-only. Bot storage, config, cogs, Reticulum config, and temp directories stay writable.
T282828
Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffSecureBotTa5d6ff"Tb4b4b4,
Te6edf3landlock_enabledTff7b72=Tff7b72TrueTb4b4b4,
Tb4b4b4)
Te6edf3status Tff7b72= Te6edf3botTff7b72.Td2a8ffget_landlock_statusTb4b4b4(Tb4b4b4)
Tffa657printTb4b4b4(Te6edf3statusTb4b4b4)
Environment overrides:
β’ T383838LXMFY_LANDLOCK=0: disable Landlock
β’ T383838LXMFY_LANDLOCK=1: force an attempt on Linux
β’ unset: follow T383838landlock_enabled and kernel auto-detection
External script cog sandbox
Executable cogs in T383838cogs/ can run in a restricted environment when T383838external_cogs_sandbox_enabled=True (default). Set T383838external_cogs_sandbox_type to:
β’ T383838auto (default): prefer Landlock, then T383838bwrap, then T383838firejail
β’ T383838landlock: Landlock-only via T383838preexec_fn
β’ T383838bwrap: bubblewrap read-only bind sandbox
β’ T383838firejail: firejail private profile with no network
β’ T383838none: no subprocess sandbox
See the docs for full configuration details.
Development
β’ Python 3.11+
β’ Poetry
T282828
poetry install
poetry run lxmfy run Tffa657echo
Common Makefile targets:
T282828
make lint T8b949e# ruff check
make typecheck T8b949e# pyright lxmfy
make Tffa657test T8b949e# pytest
make ci T8b949e# lint, typecheck, security check, test, build
Contributing
Send ideas and issues to LXMF: T3838387cc8d66b4f6a0e0e49d34af7f6077b5a
License
Served by rngit 1.5.2 - Generated in 0.06s